﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace CrashSimul8or
{
    class Menu
    {
        enum BState
        {
            HOVER,
            UP,
            JUST_RELEASED,
            DOWN
        }

        Game game;
        Color[] buttonColor;
        Rectangle[] buttonRectangle;
        BState[] buttonState;
        Texture2D[] buttonTexture;
        List<ButtonEvent> buttonEvents;
        Boolean[] playHoverSound;
        List<Color> buttonColorIdle, buttonColorHover, buttonColorPressed;

        int nrOfButtons, 
            buttonHeight, 
            buttonWidth, 
            mx, 
            my;

        double[] buttonTimer;
        double frameTime;
        bool mpressed, prev_mpressed;

        /// <summary>
        /// Smiður fyrir menu
        /// </summary>
        /// <param name="game">Leikurinn</param>
        /// <param name="container">Buttoncontainer sem hefur takkana</param>
        /// <param name="buttonWidth">Breydd takka</param>
        /// <param name="buttonHeight">Hæð takka</param>
        public Menu(Game game,
                    ButtonContainer container,
                    int buttonWidth,
                    int buttonHeight)
        {
            this.game = game;
            this.buttonEvents = container.events;
            this.buttonHeight = buttonHeight;
            this.buttonWidth = buttonWidth;
            this.buttonColorIdle = container.buttonColorIdle;
            this.buttonColorHover = container.buttonColorHover;
            this.buttonColorPressed = container.buttonColorPressed;

            nrOfButtons = container.textures.Count;
            prev_mpressed = false;
            playHoverSound = new Boolean[nrOfButtons];
            buttonColor = new Color[nrOfButtons];
            buttonRectangle = new Rectangle[nrOfButtons];
            buttonState = new BState[nrOfButtons];
            buttonTexture = new Texture2D[nrOfButtons];
            buttonTimer = new double[nrOfButtons];

            // Finna miðjuna á skjánum og raða tökkunum hvern ofan á annan
            int x = game.Window.ClientBounds.Width / 2 - buttonWidth / 2;
            int y = game.Window.ClientBounds.Height / 2 -
                nrOfButtons / 2 * buttonHeight -
                (nrOfButtons % 2) * buttonHeight / 2;

            for (int i = 0; i < nrOfButtons; i++)
            {
                buttonState[i] = BState.UP;
                buttonColor[i] = buttonColorIdle[i];
                buttonTimer[i] = 0.0;
                buttonRectangle[i] = new Rectangle(x, y, buttonWidth, buttonHeight);
                y += buttonHeight + 5; //+5 er space á milli takkanna
                buttonTexture[i] = container.textures[i];
                playHoverSound[i] = true;
            }
        }

        public Menu(Game game,
                    ButtonContainer container,
                    int buttonWidth,
                    int buttonHeight,
                    int yCords)
        {
            this.game = game;
            this.buttonEvents = container.events;
            this.buttonHeight = buttonHeight;
            this.buttonWidth = buttonWidth;
            this.buttonColorIdle = container.buttonColorIdle;
            this.buttonColorHover = container.buttonColorHover;
            this.buttonColorPressed = container.buttonColorPressed;

            nrOfButtons = container.textures.Count;
            prev_mpressed = false;
            playHoverSound = new Boolean[nrOfButtons];
            buttonColor = new Color[nrOfButtons];
            buttonRectangle = new Rectangle[nrOfButtons];
            buttonState = new BState[nrOfButtons];
            buttonTexture = new Texture2D[nrOfButtons];
            buttonTimer = new double[nrOfButtons];

            // Finna miðjuna á skjánum og raða tökkunum hvern ofan á annan
            int x = game.Window.ClientBounds.Width / 2 - buttonWidth / 2;
            int y = yCords -
                nrOfButtons / 2 * buttonHeight -
                (nrOfButtons % 2) * buttonHeight / 2;

            for (int i = 0; i < nrOfButtons; i++)
            {
                buttonState[i] = BState.UP;
                buttonColor[i] = buttonColorIdle[i];
                buttonTimer[i] = 0.0;
                buttonRectangle[i] = new Rectangle(x, y, buttonWidth, buttonHeight);
                y += buttonHeight + 5; //+5 er space á milli takkanna
                buttonTexture[i] = container.textures[i];
                playHoverSound[i] = true;
            }
        }

        /// <summary>
        /// Aðferð sem uppfærir takkana
        /// </summary>
        /// <param name="gameTime">GameTime frá leiknum</param>
        public void Update(GameTime gameTime) 
        {
            //Fá tímann í sek.
            frameTime = gameTime.ElapsedGameTime.Milliseconds / 1000.0;

            //Update músina
            MouseState mouse_state = Mouse.GetState();
            mx = mouse_state.X;
            my = mouse_state.Y;
            prev_mpressed = mpressed;
            mpressed = mouse_state.LeftButton == ButtonState.Pressed;

            updateButtons();
        }

        /// <summary>
        /// Fall sem teiknar takkana.
        /// </summary>
        /// <param name="spriteBatch">SpriteBatch til að teikna</param>
        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Begin();
            for (int i = 0; i < nrOfButtons; i++)
                spriteBatch.Draw(buttonTexture[i], buttonRectangle[i], buttonColor[i]);
            spriteBatch.End();
        }

        /// <summary>
        /// Einfaldara (Wrapper) fall fyrir textureHitAlpha
        /// </summary>
        /// <param name="tx">x hnit hjá texture</param>
        /// <param name="ty">y hnit hjá texture</param>
        /// <param name="tex">texture sem þetta á við</param>
        /// <param name="x">x hnit</param>
        /// <param name="y">y hnit</param>
        /// <returns>Svar hvort x,y sé yfir texturinu</returns>
        private Boolean textureHitAlpha(Rectangle rect, Texture2D tex, int x, int y)
        {
            return textureHitAlpha(0, 0, tex, tex.Width * (x - rect.X) /
                rect.Width, tex.Height * (y - rect.Y) / rect.Height);
        }

        /// <summary>
        /// Skoðar hvort x,y sé á texture. Annað en textureHit tekur þetta fall tillit
        /// til alpha rásar á texturinu.
        /// </summary>
        /// <param name="tx">x hnit hjá texture</param>
        /// <param name="ty">y hnit hjá texture</param>
        /// <param name="tex">texture sem þetta á við</param>
        /// <param name="x">x hnit</param>
        /// <param name="y">y hnit</param>
        /// <returns>Svar hvort x,y sé yfir texturinu</returns>
        private Boolean textureHitAlpha(float tx, float ty, Texture2D tex, int x, int y)
        {
            if (textureHit(tx, ty, tex, x, y))
            {
                uint[] data = new uint[tex.Width * tex.Height];
                tex.GetData<uint>(data);
                if ((x - (int)tx) + (y - (int)ty) *
                    tex.Width < tex.Width * tex.Height)
                {
                    return ((data[
                        (x - (int)tx) + (y - (int)ty) * tex.Width
                        ] &
                                0xFF000000) >> 24) > 20;
                }
            }
            return false;
        }

        /// <summary>
        /// Finnur hvort x,y er fyrir innan ferhyrninginn sem er utan um texturið sem er
        /// staðsett á tx,tx
        /// </summary>
        /// <param name="tx">x hnit hjá texture</param>
        /// <param name="ty">y hnit hjá texture</param>
        /// <param name="tex">texture sem þetta á við</param>
        /// <param name="x">x hnit</param>
        /// <param name="y">y hnit</param>
        /// <returns>Svar hvort x,y sé yfir ferhyrningnum</returns>
        private Boolean textureHit(float tx, float ty, Texture2D tex, int x, int y)
        {
            return (x >= tx &&
                x <= tx + tex.Width &&
                y >= ty &&
                y <= ty + tex.Height);
        }

        /// <summary>
        /// Finnur út stöðuna og lit takkanna.
        /// </summary>
        private void updateButtons()
        {
            for (int i = 0; i < nrOfButtons; i++)
            {

                if (textureHitAlpha(
                    buttonRectangle[i], buttonTexture[i], mx, my))
                {
                    buttonTimer[i] = 0.0;
                    if (mpressed)
                    {
                        //Það er verið að halda músinni niðri
                        buttonState[i] = BState.DOWN;
                        buttonColor[i] = buttonColorPressed[i];
                    }
                    else if (!mpressed && prev_mpressed)
                    {
                        //Það var verið að sleppa músinni
                        if (buttonState[i] == BState.DOWN)
                        {
                            //takki i var niðri þegar sleppt var músatakkanum
                            buttonState[i] = BState.JUST_RELEASED;
                        }
                    }
                    else
                    {
                        if (playHoverSound[i])
                        {
                            playHoverSound[i] = false;
                            if(GameVariables.soundEffects) ResourceManager.getSound("hoverButton").Play();
                        }
                        buttonState[i] = BState.HOVER;
                        buttonColor[i] = buttonColorHover[i];
                    }
                }
                else
                {
                    playHoverSound[i] = true;
                    buttonState[i] = BState.UP;
                    if (buttonTimer[i] > 0)
                    {
                        buttonTimer[i] = buttonTimer[i] - frameTime;
                    }
                    else
                    {
                        buttonColor[i] = buttonColorIdle[i];
                    }
                }

                if (buttonState[i] == BState.JUST_RELEASED)
                {
                    buttonPressed(i);
                }
            }
        }

        /// <summary>
        /// Kallar á það fall sem takkinn er bundinn við.
        /// </summary>
        /// <param name="i">Takkinn sem þetta á við</param>
        private void buttonPressed(int i)
        {
            buttonEvents[i].buttonPressed();
        }
    }
}
